#include "Vector4.h"
#include <cassert>
#include <cmath>


const float   Vector4::EQUALLIMIT = 0.0001f;
const Vector4 Vector4::ZERO  ( 0, 0, 0, 0 );
const Vector4 Vector4::UNIT_X( 1, 0, 0, 0 );
const Vector4 Vector4::UNIT_Y( 0, 1, 0, 0 );
const Vector4 Vector4::UNIT_Z( 0, 0, 1, 0 );
const Vector4 Vector4::UNIT_W( 0, 0, 0, 1 );

Vector4::Vector4()
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] = 0;
	}
}

Vector4::Vector4( const Vector4& v )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] = v.mElement[i];
	}
}

Vector4::Vector4( float x, float y, float z, float w )
: mX( x ),
  mY( y ),
  mZ( z ),
  mW( w )
{
}

Vector4::Vector4( const float data[ELEMENTCOUNT] )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] = data[i];
	}
}

Vector4::Vector4( const int data[ELEMENTCOUNT] )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] = (float)data[i];
	}
}

Vector4::~Vector4()
{
}

float Vector4::operator[]( unsigned int i ) const
{
	assert( i < ELEMENTCOUNT );

	return mElement[i];
}

float& Vector4::operator[]( unsigned int i )
{
	assert( i < ELEMENTCOUNT );

	return mElement[i];
}

const Vector4& Vector4::operator+() const
{
	return *this;
}

Vector4 Vector4::operator-() const
{
	return *this * -1;
}

Vector4 Vector4::operator+( const Vector4& v ) const
{
	Vector4 v2( *this );
	v2 += v;

	return v2;
}

Vector4 Vector4::operator-( const Vector4& v ) const
{
	Vector4 v2( *this );
	v2 -= v;

	return v2;
}

Vector4 Vector4::operator*( float s ) const
{
	Vector4 v2( *this );
	v2 *= s;

	return v2;
}

Vector4 Vector4::operator/( float s ) const
{
	assert( s );

	Vector4 v2( *this );
	v2 /= s;

	return v2;
}

Vector4& Vector4::operator=( const Vector4& v )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] = v.mElement[i];
	}

	return *this;
}

Vector4& Vector4::operator+=( const Vector4& v )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] += v.mElement[i];
	}

	return *this;
}

Vector4& Vector4::operator-=( const Vector4& v )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] -= v.mElement[i];
	}

	return *this;
}

Vector4& Vector4::operator*=( float s )
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] *= s;
	}

	return *this;
}

Vector4& Vector4::operator/=( float s )
{
	assert( s );

	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		mElement[i] /= s;
	}

	return *this;
}

bool Vector4::operator==( const Vector4& v ) const
{
	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		if( fabs( mElement[i] - v.mElement[i] ) > EQUALLIMIT ) return false;
	}

	return true;
}

bool Vector4::operator!=( const Vector4& v ) const
{
	return *this == v;
}

float Vector4::Dot( const Vector4& v ) const
{
	float value = 0;

	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		value += mElement[i] * v.mElement[i];
	}

	return value;
}

float Vector4::GetSquaredLength() const
{
	float value = 0;

	for( unsigned int i = 0; i < ELEMENTCOUNT; ++i )
	{
		value += mElement[i] * mElement[i];
	}

	return value;
}

float Vector4::GetLength() const
{
	return sqrt( GetSquaredLength() );
}

Vector4& Vector4::Normalize()
{
	*this /= GetLength();
	return *this;
}

Vector4 operator*( float s, const Vector4& v )
{
	return v * s;
}

std::ostream& operator <<( std::ostream& o, const Vector4& v )
{
	o << "( ";
	for( unsigned int i = 0; i < Vector4::ELEMENTCOUNT; ++i )
	{
		o << v.mElement[i];
		if( i != Vector4::ELEMENTCOUNT - 1 ) o << ", ";
	}
	o << " )";

	return o;
}

